﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockShark.Models;
using System.Net;

namespace StockShark
{
    public class StockQuotesParser
    {
        public List<string> UriList;                        // lista uri z adresami stron do parsowania danych
        public List<Instrument> ContinuousIndexesList;      // notowania ciągłe - indeksy
        public List<Instrument> ContinuousInstrumentsList;  // notowania ciągłe - akcje
        public List<Instrument> UniformInstrumentsList;     // notowania jednolite - akcje
        public List<Instrument> NewConnectInstrumentsList;  // notowania New Connect - akcje
        public List<Instrument> NewConnectIndexesList;      // notowania New Connect - indeksy
        public List<Material> MaterialsList;                // surowce
        public List<Currency> CurrenciesList;               // waluty

        public StockQuotesParser() 
        {
            ContinuousIndexesList = new List<Instrument>();
            ContinuousInstrumentsList = new List<Instrument>();
            UniformInstrumentsList = new List<Instrument>();
            NewConnectInstrumentsList = new List<Instrument>();
            NewConnectIndexesList = new List<Instrument>();
            MaterialsList = new List<Material>();
            CurrenciesList = new List<Currency>();
            UriList = new List<string>();
        }

        /// <summary>
        /// Metoda służąca do parsowania danych giełdowych
        /// </summary>
        /// <returns></returns>
        public int Parse()
        {
            WebClient client = new WebClient();
            try
            {
                /* notowania ciągłe */
                client.Encoding = System.Text.UTF8Encoding.UTF8;
                string result = client.DownloadString(UriList[0]);
                int value = ParsingAlgorithmForContinuousInstrumentsAndNewConnect(result, false);
                
                if (value == -1 || value == 0) 
                {
                    ContinuousIndexesList.Clear();
                    ContinuousInstrumentsList.Clear();
                    UniformInstrumentsList.Clear();
                    NewConnectInstrumentsList.Clear();
                    NewConnectIndexesList.Clear();
                    MaterialsList.Clear();
                    CurrenciesList.Clear();
                    return value;
                }

                /* notowania z New Connect */
                result = client.DownloadString(UriList[1]);
                value = ParsingAlgorithmForContinuousInstrumentsAndNewConnect(result, true);

                if (value == -1 || value == 0)
                {
                    ContinuousIndexesList.Clear();
                    ContinuousInstrumentsList.Clear();
                    UniformInstrumentsList.Clear();
                    NewConnectInstrumentsList.Clear();
                    NewConnectIndexesList.Clear();
                    MaterialsList.Clear();
                    CurrenciesList.Clear();
                    return value;
                }

                /* notowania walut */
                result = client.DownloadString(UriList[2]);
                value = ParsingAlgorithmForCurrencies(result);

                if (value == -1 || value == 0)
                {
                    ContinuousIndexesList.Clear();
                    ContinuousInstrumentsList.Clear();
                    UniformInstrumentsList.Clear();
                    NewConnectInstrumentsList.Clear();
                    NewConnectIndexesList.Clear();
                    MaterialsList.Clear();
                    CurrenciesList.Clear();
                    return value;
                }

                /* notowania surowców */
                result = client.DownloadString(UriList[3]);
                value = ParsingAlgorithmForMaterials(result);

                if (value == -1 || value == 0)
                {
                    ContinuousIndexesList.Clear();
                    ContinuousInstrumentsList.Clear();
                    UniformInstrumentsList.Clear();
                    NewConnectInstrumentsList.Clear();
                    NewConnectIndexesList.Clear();
                    MaterialsList.Clear();
                    CurrenciesList.Clear();
                    return value;
                }

                /* notowania towarów */
                result = client.DownloadString(UriList[4]);
                value = ParsingAlgorithmForArticles(result);

                if (value == -1 || value == 0)
                {
                    ContinuousIndexesList.Clear();
                    ContinuousInstrumentsList.Clear();
                    UniformInstrumentsList.Clear();
                    NewConnectInstrumentsList.Clear();
                    NewConnectIndexesList.Clear();
                    MaterialsList.Clear();
                    CurrenciesList.Clear();
                    return value;
                }

                /* notowania jednolite */
                result = client.DownloadString(UriList[5]);
                value = ParsingAlgorithmForUniformInstruments(result);
                
                if (value == -1)
                {
                    ContinuousIndexesList.Clear();
                    ContinuousInstrumentsList.Clear();
                    UniformInstrumentsList.Clear();
                    NewConnectInstrumentsList.Clear();
                    NewConnectIndexesList.Clear();
                    MaterialsList.Clear();
                    CurrenciesList.Clear();
                    return value;
                }

                return value;
            }
            catch
            {
                ContinuousIndexesList.Clear();
                ContinuousInstrumentsList.Clear();
                UniformInstrumentsList.Clear();
                NewConnectInstrumentsList.Clear();
                NewConnectIndexesList.Clear();
                MaterialsList.Clear();
                CurrenciesList.Clear();
                return -1;
            }
        }

        /// <summary>
        /// Metoda służąca parsowaniu wszystkich ciągłych indeksów, akcji oraz indeksów, akcji z New Connect
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę</param>
        /// <param name="isNewConnect">czy pobierać wartości z new connect</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, -1 - błąd operacji</returns>
        public int ParsingAlgorithmForContinuousInstrumentsAndNewConnect(string result, bool isNewConnect)
        {
            if(string.IsNullOrWhiteSpace(result))
            {
                return -1;
            }

            result = result.Replace("\t", "");
            result = result.Replace("\r", "");
            result = result.Replace("\n", "");
            int i = result.IndexOf("Thover\">");

            if (i == -1) 
            {
                return -1;
            }

            int j, k, l;
            Instrument temp;
            result = result.Substring(i);

            while (result.Contains("Thover\">"))
            {
                temp = new Instrument();
                i = result.IndexOf("title=");
                j = result.IndexOf("</a>");
                temp.Name = result.Substring(i + 7, j - (i + 7));
                temp.Name = temp.Name.Substring(0, temp.Name.IndexOf("\""));

                i = result.IndexOf("bold textright\">");
                result = result.Substring(i + 16);
                j = result.IndexOf("</td>");
                string strNumber = result.Substring(0, j);
                strNumber = strNumber.Replace(" ", "");
                k = strNumber.IndexOf("[");

                if (k > 0)
                {
                    k = strNumber.IndexOf("<br/>");
                    strNumber = strNumber.Replace(strNumber.Substring(k), "");
                }
                else 
                {
                    strNumber = strNumber.Replace("<br/>", "");
                    strNumber = strNumber.Replace("[", "");
                    strNumber = strNumber.Replace("]", "");
                }
                
                if (strNumber != "---")
                {
                    temp.CurrentPrice = Decimal.Parse(strNumber);
                }
                else
                {
                    temp.CurrentPrice = 0;
                }

                result = result.Substring(j);
                i = result.IndexOf("Thover\">");
                if (i != -1)
                {
                    result = result.Substring(i);
                }

                if (isNewConnect) 
                {
                    if (temp.Name.ToLower().StartsWith("nc"))
                    {
                        NewConnectIndexesList.Add(temp);
                    }
                    else 
                    {
                        NewConnectInstrumentsList.Add(temp);
                    }
                }
                else if (temp.Name.ToLower().Contains("wig") || temp.Name.ToLower().Contains("tbsp") || temp.Name.Contains("InvestorMS") || temp.Name.Contains("RESPECT"))
                {
                    ContinuousIndexesList.Add(temp);
                }
                else 
                {
                    ContinuousInstrumentsList.Add(temp);
                }
            }
            return 1;
        }

        /// <summary>
        /// Metoda służąca parsowaniu jednolitych akcji
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, 0 - operacja nie przeprowadzona ze względu
        /// na nieodpowiedni czas, -1 - błąd operacji</returns>
        public int ParsingAlgorithmForUniformInstruments(string result){

            if (string.IsNullOrWhiteSpace(result))
            {
                return -1;
            }

            List<Instrument> data = new List<Instrument>();
            int decision = TimeCounterForParsing(DateTime.Now);
            int stateOfMethod = 0;     // czy poprawnie przeprowadzono operację

            switch(decision){
                case 0:
                    break;
                
                case 1:
                    stateOfMethod = ParseFirstFix(result);
                    break;

                case 2:
                    stateOfMethod = ParseSecondFix(result);
                    break;
            };

            return stateOfMethod;
        }

        /// <summary>
        /// Metoda wyznaczająca na podstawie czasu czy fix ma być pobierany i który fix trzeba ewentualnie pobrać
        /// </summary>
        /// <param name="now">aktualny czas</param>
        /// <returns>1 - czas pomiędzy 11.15 a 11.30 - pierwszy fix, 2 - czas pomiędzy 15.15 a 15.30 drugi fix,
        /// 0 - nieodopowiedni czas do pobierania jakiegokolwiek fixu</returns>
        public int TimeCounterForParsing(DateTime now)
        {
            if (now.Hour == 11 && now.Minute >= 15 && now.Minute <= 30) 
            {
                return 1;
            }
            else if (now.Hour == 15 && now.Minute == 15 && now.Minute <= 30)
            {
                return 2;
            }
            else 
            {
                return 0;
            }
        }

        /// <summary>
        /// Parsowanie pierwszego fixa dla notowań jednolitych
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, 0 - operacja nie przeprowadzona ze względu
        /// na nieodpowiedni czas, -1 - błąd operacji</returns>
        public int ParseFirstFix(string result)
        {
            result = result.Replace("\t", "");
            result = result.Replace("\r", "");
            result = result.Replace("\n", "");
            int i = result.IndexOf("Thover\">");

            if (i == -1)
            {
                return -1;
            }

            int j;
            Instrument temp;
            result = result.Substring(i);

            while (result.Contains("Thover\">"))
            {
                temp = new Instrument();
                i = result.IndexOf("title=");
                j = result.IndexOf("</a>");
                temp.Name = result.Substring(i + 7, j - (i + 7));
                temp.Name = temp.Name.Substring(0, temp.Name.IndexOf("\""));

                i = result.IndexOf("bold textright\">");
                result = result.Substring(i + 16);
                j = result.IndexOf("<br/>");
                string strNumber = result.Substring(0, j);
                strNumber = strNumber.Replace(" ", "");
                strNumber = strNumber.Replace("<br/>", "");
                strNumber = strNumber.Replace("[", "");
                strNumber = strNumber.Replace("]", "");
                if (strNumber != "---")
                {
                    temp.CurrentPrice = Decimal.Parse(strNumber);
                }
                else
                {
                    temp.CurrentPrice = 0;
                }

                result = result.Substring(j);
                i = result.IndexOf("Thover\">");
                if (i != -1)
                {
                    result = result.Substring(i);
                }
                UniformInstrumentsList.Add(temp);
            }
            return 1;
        }

        /// <summary>
        /// Parsowanie drugiego fixa dla notowań jednolitych
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, 0 - operacja nie przeprowadzona ze względu
        /// na nieodpowiedni czas, -1 - błąd operacji</returns>
        public int ParseSecondFix(string result)
        {
            result = result.Replace("\t", "");
            result = result.Replace("\r", "");
            result = result.Replace("\n", "");
            int i = result.IndexOf("Thover\">");

            if (i == -1)
            {
                return -1;
            }

            int j;
            Instrument temp;
            result = result.Substring(i);

            while (result.Contains("Thover\">"))
            {
                temp = new Instrument();
                i = result.IndexOf("title=");
                j = result.IndexOf("</a>");
                temp.Name = result.Substring(i + 7, j - (i + 7));
                temp.Name = temp.Name.Substring(0, temp.Name.IndexOf("\""));

                i = result.IndexOf("bold textright\">");
                result = result.Substring(i + 16);
                i = result.IndexOf("<br/>");
                j = result.IndexOf("</td>");
                string strNumber = result.Substring(i+6, j - (i + 6));
                strNumber = strNumber.Replace(" ", "");

                if (strNumber != "---")
                {
                    temp.CurrentPrice = Decimal.Parse(strNumber);
                }
                else
                {
                    temp.CurrentPrice = 0;
                }

                result = result.Substring(j);
                i = result.IndexOf("Thover\">");
                if (i != -1)
                {
                    result = result.Substring(i);
                }
                UniformInstrumentsList.Add(temp);
            }
            return 1;
        }

        /// <summary>
        /// Metoda służąca parsowaniu notowań surowców
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę w utf-8</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, -1 - błąd operacji</returns>
        public int ParsingAlgorithmForMaterials(string result)
        {
            result = result.Replace("\t", "");
            result = result.Replace("\r", "");
            result = result.Replace("\n", "");
            int i = result.IndexOf("Thover\">");

            if (i == -1)
            {
                return -1;
            }

            int j;
            Material temp;
            result = result.Substring(i);

            // notowania w USD, aby zmienić na PLN należy wymnożyć wartość przez odpowiedni kurs
            decimal factor = 1;
            foreach(Currency currency in CurrenciesList)
            {
                if (currency.Name.Equals("USD/PLN")) 
                {
                    factor = currency.CurrentPrice;
                    break;
                }
            }

            while (result.Contains("Thover\">"))
            {
                temp = new Material();
                i = result.IndexOf("title=");
                j = result.IndexOf("</a>");
                temp.Name = result.Substring(i + 7, j - (i + 7));
                temp.Name = temp.Name.Substring(0, temp.Name.IndexOf("\""));

                i = result.IndexOf("bold textright\">");
                result = result.Substring(i + 16);
                i = result.IndexOf("</td>");
                string strNumber = result.Substring(0, i);
                strNumber = strNumber.Replace(" ", "");

                if (strNumber != "---")
                {
                    temp.CurrentPrice = Decimal.Parse(strNumber);
                    temp.CurrentPrice = temp.CurrentPrice * factor;     // zmiana z USD na PLN
                }
                else
                {
                    temp.CurrentPrice = 0;
                }

                result = result.Substring(i);
                i = result.IndexOf("Thover\">");
                if (i != -1)
                {
                    result = result.Substring(i);
                }
                MaterialsList.Add(temp);
            }
            return 1;
        }

        /// <summary>
        /// Metoda służąca parsowaniu notowań walut
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, -1 - błąd operacji</returns>
        public int ParsingAlgorithmForCurrencies(string result)
        {
            result = result.Replace("\t", "");
            result = result.Replace("\r", "");
            result = result.Replace("\n", "");
            int i = result.IndexOf("sULineBold\">");

            if (i == -1)
            {
                return -1;
            }
            int j;
            Currency temp;
            result = result.Substring(i);

            while (result.Contains("sULineBold\">"))
            {
                temp = new Currency();
                i = result.IndexOf("profile-waluta-online\">");
                j = result.IndexOf("</a>");
                temp.Name = result.Substring(i + 23, j - (i + 23));

                i = result.IndexOf("txtBold\">");
                result = result.Substring(i + 9);
                i = result.IndexOf("</span>");
                string strNumber = result.Substring(0, i);
                strNumber = strNumber.Replace(" ", "");

                if (strNumber != "---")
                {
                    temp.CurrentPrice = Decimal.Parse(strNumber);
                }
                else
                {
                    temp.CurrentPrice = 0;
                }

                result = result.Substring(i);
                i = result.IndexOf("sULineBold\">");
                if (i != -1)
                {
                    result = result.Substring(i);
                }
                CurrenciesList.Add(temp);
            }
            return 1;
        }

        /// <summary>
        /// Metoda służąca parsowaniu notowań towarów; dane zapisywane w liście materials
        /// </summary>
        /// <param name="result">string zawierający sparsowaną stronę w utf-8</param>
        /// <returns>1 - poprawnie przeprowadzona operacja, -1 - błąd operacji</returns>
        public int ParsingAlgorithmForArticles(string result)
        {
            result = result.Replace("\t", "");
            result = result.Replace("\r", "");
            result = result.Replace("\n", "");
            int i = result.IndexOf("Thover\">");

            if (i == -1)
            {
                return -1;
            }

            int j;
            Material temp;
            result = result.Substring(i);

            // notowania w USD, aby zmienić na PLN należy wymnożyć wartość przez odpowiedni kurs
            decimal factor = 1;
            foreach (Currency currency in CurrenciesList)
            {
                if (currency.Name.Equals("USD/PLN"))
                {
                    factor = currency.CurrentPrice;
                    break;
                }
            }

            while (result.Contains("Thover\">"))
            {
                temp = new Material();
                i = result.IndexOf("title=");
                j = result.IndexOf("</a>");
                temp.Name = result.Substring(i + 7, j - (i + 7));
                temp.Name = temp.Name.Substring(0, temp.Name.IndexOf("\""));

                i = result.IndexOf("bold textright\">");
                result = result.Substring(i + 16);
                i = result.IndexOf("</td>");
                string strNumber = result.Substring(0, i);
                strNumber = strNumber.Replace(" ", "");

                if (strNumber != "---")
                {
                    temp.CurrentPrice = Decimal.Parse(strNumber);
                    temp.CurrentPrice = temp.CurrentPrice * factor;     // zmiana z USD na PLN
                }
                else
                {
                    temp.CurrentPrice = 0;
                }

                result = result.Substring(i);
                i = result.IndexOf("Thover\">");
                if (i != -1)
                {
                    result = result.Substring(i);
                }
                MaterialsList.Add(temp);
            }
            return 1;
        }
    }
}